package com.atlin.license;

import org.apache.commons.lang3.StringUtils;
import oshi.SystemInfo;
import oshi.hardware.ComputerSystem;
import oshi.hardware.HardwareAbstractionLayer;

import java.io.*;
import java.net.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * 通用版：支持 Windows / Linux / Docker 环境的服务器硬件信息采集
 */
public class CrossPlatformServerInfos extends AbstractServerInfos {

    @Override
    protected List<String> getIpAddress() throws Exception {
        List<String> result = new ArrayList<>();

        // 获取所有 IP
        Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
        while (interfaces.hasMoreElements()) {
            NetworkInterface iface = interfaces.nextElement();

            if (iface == null || !iface.isUp() || iface.isLoopback() || iface.isVirtual()) {
                continue;
            }

            Enumeration<InetAddress> inetAddresses = iface.getInetAddresses();
            while (inetAddresses.hasMoreElements()) {
                InetAddress inetAddr = inetAddresses.nextElement();
                if (!(inetAddr.isLoopbackAddress()
                        || inetAddr.isLinkLocalAddress()
                        || inetAddr.isMulticastAddress()
                        || inetAddr.getHostAddress().contains(":"))) {
                    result.add(inetAddr.getHostAddress());
                }
            }
        }

        // 如果运行在容器中，补上宿主机 IP
        String hostIp = getHostIpInContainer();
        if (hostIp != null && !result.contains(hostIp)) {
            result.add(hostIp);
        }

        return result.stream().distinct().sorted().collect(Collectors.toList());
    }

    @Override
    protected List<String> getMacAddress() throws Exception {
        List<String> result = new ArrayList<>();

        Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
        while (interfaces.hasMoreElements()) {
            NetworkInterface iface = interfaces.nextElement();
            if (iface == null || !iface.isUp() || iface.isLoopback() || iface.isVirtual()) {
                continue;
            }

            byte[] mac = iface.getHardwareAddress();
            if (mac != null && mac.length > 0) {
                String macAddr = IntStream.range(0, mac.length)
                        .mapToObj(i -> String.format("%02X", mac[i]))
                        .collect(Collectors.joining("-"));
                result.add(macAddr);
            }
        }

        return result.stream().distinct().sorted().collect(Collectors.toList());
    }

    @Override
    protected String getCPUSerial() throws Exception {
/*        if (isWindows()) {
            // 执行命令并过滤掉 header
            String output = execCmdAndGetLine("wmic cpu get ProcessorId");
            if (StringUtils.isNotBlank(output)) {
                // 拆分多行并过滤掉 header
                for (String line : output.split("\\r?\\n")) {
                    line = line.trim();
                    if (StringUtils.isBlank(line)) continue;
                    if (line.equalsIgnoreCase("ProcessorId")) continue; // 跳过标题行
                    return line; // 返回第一个非空且非标题的行
                }
            }
            return "";
        } else {
            // 优先读取 /sys/class/dmi/id/product_uuid 或 processor/cpuinfo
            String serial = readFileIfExists("/sys/class/dmi/id/product_uuid");
            if (StringUtils.isNotBlank(serial)) return serial.trim();

            // 其次读取 /proc/cpuinfo
            String cpuInfo = execCmdAndGetLine("cat /proc/cpuinfo | grep 'Serial' | awk '{print $3}'");
            if (StringUtils.isNotBlank(cpuInfo)) return cpuInfo.trim();

            // 再次尝试 dmidecode（宿主机）
            return execCmdAndGetLine("dmidecode -t processor | grep 'ID' | awk -F ':' '{print $2}' | head -n 1");
        }*/
        SystemInfo si = new SystemInfo();
        HardwareAbstractionLayer hal = si.getHardware();
        return hal.getProcessor().getProcessorIdentifier().getProcessorID();
    }

    @Override
    protected String getMainBoardSerial() throws Exception {
/*        if (isWindows()) {
            return execCmdAndGetLine("wmic baseboard get SerialNumber");
        } else {
            // 优先读取挂载的宿主机硬件信息
            String serial = readFileIfExists("/sys/class/dmi/id/board_serial");
            if (StringUtils.isNotBlank(serial) && !"None".equalsIgnoreCase(serial)) return serial.trim();

            serial = readFileIfExists("/sys/class/dmi/id/product_serial");
            if (StringUtils.isNotBlank(serial)) return serial.trim();

            // 最后尝试 dmidecode（宿主机）
            return execCmdAndGetLine("dmidecode -t baseboard | grep 'Serial Number' | awk -F ':' '{print $2}' | head -n 1");
        }*/
        SystemInfo si = new SystemInfo();
        HardwareAbstractionLayer hal = si.getHardware();

        // 1. 主板序列号 (相对可靠)
        ComputerSystem computerSystem = hal.getComputerSystem();
        return computerSystem.getBaseboard().getSerialNumber();
    }

    // ===========================================
    // 辅助方法
    // ===========================================

    private boolean isWindows() {
        return System.getProperty("os.name").toLowerCase().contains("win");
    }
    
    private String execCmdAndGetLine(String cmd) {
        try {
            Process process;
            if (isWindows()) {
                process = Runtime.getRuntime().exec(new String[]{"cmd", "/c", cmd});
            } else {
                process = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", cmd});
            }

            try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
                return reader.lines()
                        .map(String::trim) // 去掉前后空格
                        .filter(line -> StringUtils.isNotBlank(line)) // 非空
                        .filter(line -> {
                            if (isWindows()) {
                                // Windows 平台，过滤掉常见 header
                                String low = line.toLowerCase();
                                return !(low.contains("processorid") || low.contains("serialnumber") || low.contains("uuid"));
                            } else {
                                // Linux 平台，过滤掉包含 "serial" 的行（原有逻辑）
                                return !line.toLowerCase().contains("serial");
                            }
                        })
                        .findFirst()
                        .orElse("");
            }
        } catch (Exception e) {
            return "";
        }
    }


    private String readFileIfExists(String path) {
        try {
            File file = new File(path);
            if (file.exists() && file.canRead()) {
                return Files.readAllLines(Paths.get(path)).stream()
                        .filter(StringUtils::isNotBlank)
                        .findFirst()
                        .orElse("");
            }
        } catch (Exception ignored) {
        }
        return "";
    }

    private String getHostIpInContainer() {
        try {
            // 判断是否容器
            if (!isRunningInContainer()) return null;

            String envIp = System.getenv("HOST_IP");
            if (envIp != null && !envIp.isBlank()) {
                return envIp.trim();
            }
            
            // 尝试 /etc/hosts
            try (BufferedReader reader = new BufferedReader(new FileReader("/etc/hosts"))) {
                String last = null;
                for (String line; (line = reader.readLine()) != null; ) {
                    last = line;
                }
                if (last != null && last.matches("^(\\d+\\.\\d+\\.\\d+\\.\\d+).*")) {
                    return last.split("\\s+")[0];
                }
            }

            // 尝试默认路由
            String route = execCmdAndGetLine("ip route | grep default");
            if (route.contains("via")) {
                String[] parts = route.split("\\s+");
                int viaIdx = Arrays.asList(parts).indexOf("via");
                if (viaIdx >= 0 && viaIdx + 1 < parts.length) {
                    return parts[viaIdx + 1];
                }
            }
        } catch (Exception ignored) {
        }
        return null;
    }

    private boolean isRunningInContainer() {
        try (BufferedReader reader = new BufferedReader(new FileReader("/proc/1/cgroup"))) {
            return reader.lines().anyMatch(line ->
                    line.contains("docker") || line.contains("kubepods"));
        } catch (Exception e) {
            return false;
        }
    }
}
